namespace OFX.Aggregator.WpfApplication
{
	#region #using Directives

	using System;
	using System.Collections;
	using System.Collections.Generic;
	using System.Diagnostics;
	using System.Linq;
	using System.Windows;
	using System.Windows.Controls;
	using System.Windows.Input;

	using Infrastructure;

	using Properties;

	#endregion

	/// <summary>
	/// Interaction logic for StatementSourceListPage.xaml
	/// </summary>
	public partial class StatementSourceListPage : Page
	{
		#region Commands

		public static RoutedCommand StatementSource_Config = new RoutedCommand("StatementSource_Config", typeof(StatementSourceListPage));

		public static RoutedCommand StatementSource_Create = new RoutedCommand("StatementSource_Create", typeof(StatementSourceListPage));

		public static RoutedCommand StatementSource_Delete = new RoutedCommand("StatementSource_Delete", typeof(StatementSourceListPage));

		public static RoutedCommand StatementSource_Fetch = new RoutedCommand("StatementSource_Fetch", typeof(StatementSourceListPage));

		public static RoutedCommand StatementSource_FetchAll = new RoutedCommand("StatementSource_FetchAll", typeof(StatementSourceListPage));

		#endregion

		#region Private Fields

		private static readonly List<StatementSource> statementSourceFetchQueue = new List<StatementSource>();
		private readonly IIocContainerAbstraction container;
		private bool workflowRunning;

		#endregion

		// Using a DependencyProperty as the backing store for StatementSources.  This enables animation, styling, binding, etc...
		public static readonly DependencyProperty StatementSourcesProperty = DependencyProperty.Register("StatementSources", typeof(IList<StatementSource>),
		                                                                                                 typeof(StatementSourceListPage),
		                                                                                                 new UIPropertyMetadata(null));

		public StatementSourceListPage()
		{
			this.container = SingletonContainer.Resolve<IIocContainerAbstraction>();

			var statementSourceRepository = this.container.Resolve<IStatementSourceRepository>();

			StatementSources = statementSourceRepository.StatementSources;

			InitializeComponent();
		}

		public IList<StatementSource> StatementSources
		{
			get { return (IList<StatementSource>) GetValue(StatementSourcesProperty); }
			set { SetValue(StatementSourcesProperty, value); }
		}

		#region Event Handlers

		private void workflow_WorkflowStarted(object sender, EventArgs e)
		{
			Debug.Assert(!this.workflowRunning);

			var workflow = (IStatementProcessingWorkflow) sender;

			this.workflowRunning = true;
			Cursor = Cursors.Wait;
			ForceCursor = true;

			var page = this.container.Resolve<Page>("FetchStatementProgressPage", new Dictionary<string, object>
			                                                                      	{
			                                                                      		{"source", workflow.StatementSource}
			                                                                      	});

			NavigationService.Navigate(page);
		}

		private void workflow_WorkflowFinished(object sender, EventArgs e)
		{
			var workflow = (IStatementProcessingWorkflow) sender;
			workflow.WorkflowStarted -= workflow_WorkflowStarted;
			workflow.WorkflowFinished -= workflow_WorkflowFinished;

			this.workflowRunning = false;

			Settings.Default.Save(); // Ensure the update gets registered 

			Cursor = Cursors.Arrow;
			ForceCursor = false;
		}

		private void OnNavigationServiceAvailable()
		{
			if (statementSourceFetchQueue.Any())
			{
				var nextStatementSource = statementSourceFetchQueue.First();
				statementSourceFetchQueue.RemoveAt(0);
				while (statementSourceFetchQueue.Any() && !nextStatementSource.Retrieval.CanRetrieveStatement)
				{
					nextStatementSource = statementSourceFetchQueue.First();
					statementSourceFetchQueue.RemoveAt(0);
				}

				fetchStatement(nextStatementSource);
			}
		}

		#endregion

		#region Command Handlers

		private void CanFetchStatement(object sender, CanExecuteRoutedEventArgs e)
		{
			var statementSource = (StatementSource) e.Parameter;

			e.CanExecute = (statementSource != null && statementSource.Retrieval.CanRetrieveStatement && !this.workflowRunning);
		}

		private void FetchStatement(object sender, ExecutedRoutedEventArgs e)
		{
			var statementSource = (StatementSource) e.Parameter;
			if (statementSource != null)
			{
				fetchStatement(statementSource);
			}
		}

		private void CanFetchAllStatements(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = !this.workflowRunning && StatementSources.Any(x => x.Retrieval.CanRetrieveStatement);
		}

		private void FetchAllStatements(object sender, ExecutedRoutedEventArgs e)
		{
			if (StatementSources.Any())
			{
				if (StatementSources.Count > 1)
				{
					statementSourceFetchQueue.AddRange(StatementSources.Skip(1));
				}
				fetchStatement(StatementSources.First());
			}
		}

		private void fetchStatement(StatementSource statementSource)
		{
			if (statementSource.Retrieval.CanRetrieveStatement)
			{
				var workflow = this.container.Resolve<IStatementProcessingWorkflow>(new Dictionary<string, object>
				                                                                    	{
				                                                                    		{"statementSource", statementSource}
				                                                                    	});

				workflow.WorkflowStarted += workflow_WorkflowStarted;
				workflow.WorkflowFinished += workflow_WorkflowFinished;
				workflow.PerformWorkflow();
			}
		}

		private void CanDeleteStatementSource(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = (e.Parameter != null && ((ICollection) e.Parameter).Count != 0 && !this.workflowRunning);
		}

		private void DeleteStatementSource(object sender, ExecutedRoutedEventArgs e)
		{
			foreach (StatementSource statementSource in new ArrayList((ICollection) e.Parameter))
			{
				StatementSources.Remove(statementSource);
			}
		}

		private void CanConfigStatementSource(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = (e.Parameter is StatementSource && !this.workflowRunning);
		}

		private void ConfigStatementSource(object sender, ExecutedRoutedEventArgs e)
		{
			var statementSource = (StatementSource) e.Parameter;
			var page = this.container.Resolve<AccountSetupPage>(new Dictionary<string, object>
			                                                    	{
			                                                    		{"statementSourceToEdit", statementSource}
			                                                    	});

			NavigationService.Navigate(page);
		}

		private void CanCreateStatementSource(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = true;
		}

		private void CreateStatementSource(object sender, ExecutedRoutedEventArgs e)
		{
			var page = this.container.Resolve<AccountTypeSelectionPage>();
			NavigationService.Navigate(page);
		}

		protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
		{
			if (e.Property.Name == "NavigationService")
			{
				if (NavigationService != null)
				{
					OnNavigationServiceAvailable();
				}
			}

			base.OnPropertyChanged(e);
		}

		#endregion
	}
}